/***************************************************************************
 *   Copyright (C) 2008 by Rysiek Król,,,   *
 *   rysiek@Babylon2   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "finder.h"

#include <QDir>
#include <QRegExp>
#include <QFileInfo>
#include <QApplication>
#include <QIcon>
#include <QPixmap>

#include "picturelistwidgetitem.h"
#include "searchparameter.h"
#include "viewerconstants.h"
#include "searchupdateevent.h"
#include "utils.h"
#include "searchdirupdateevent.h"

/**
 * Default constructor
 * @param parameter - search criteria object
 * @param eventHandler - target event Handler
 */
Finder::Finder(SearchParameter *parameter, QObject *eventHandler):QThread(), parameter(parameter) 
{
this->eventHandler = eventHandler;
this->start(QThread::HighPriority);
}


/**
 * Destructor
 */
Finder::~Finder()
{
}

/**
 * Main thread function
 */
void Finder::run()
{
	this->search(this->parameter->getDir());
	QApplication::postEvent (this->eventHandler, new SearchDirUpdateEvent (new QString(tr("Search finished")) ));
}

/**
 * Main Search Engine
 * @param dir - Directory that needs to be search
 */
void Finder::search(QDir *dir)
{
    QPair<QList<QFileInfo*>*,QList<QDir*>*> *dirContents = this->loadDir(*dir);
    if (this->parameter->getParameters()->contains(SearchParameter::FileName)) this->filterByName(dirContents->first);
    QList< PictureListWidgetItem * > *items = this->decodeComments(dirContents->first);
    if (this->parameter->getParameters()->contains(SearchParameter::Place)) this->filterByPlaces(items);
    if (this->parameter->getParameters()->contains(SearchParameter::Note)) this->filterByNotes(items);
    if (!this->parameter->getKeywords()->isEmpty()) this->filterByKeywords(items);
    this->filterByDate(items);
    this->sendResults(items);

    if (this->parameter->getRecursive())
    {
        for (QList<QDir*>::iterator i = dirContents->second->begin(); i != dirContents->second->end(); i++)
        {
        QApplication::postEvent (this->eventHandler, new SearchDirUpdateEvent (new QString((*i)->path())) );
            this->search(*i);
        }
    }
    delete dirContents;
}


/**
 *  Wczytywanie katalogu do zmiennej QPair osobno pliki, osobno katalogi
 * @param dir 
 * @return 
 */
QPair< QList < QFileInfo * > *, QList < QDir * > * >* Finder::loadDir(QDir dir)
{
//Filling directories
    QList < QDir * > *dirs = new QList<QDir*>();
    if (this->parameter->getRecursive())
    {
        QStringList list = dir.entryList(QDir::Dirs|QDir::NoDotAndDotDot);
        for (QList<QString>::const_iterator iterator = list.begin(); iterator != list.end(); iterator++)
        {
            QDir *tmp = new QDir(*iterator);
            if (tmp->dirName() != ".comments")
            {
                dirs->append(new QDir(dir.filePath(*iterator)));
            }
            else
            {
                delete tmp;
            }
        }
    }
    //Filling files
    QList < QFileInfo * > *files = new QList<QFileInfo*>();
    ViewerConstants constants;
    QFileInfoList list = dir.entryInfoList(constants.getFilters() , QDir::Files);
    for (QList<QFileInfo>::const_iterator iterator = list.begin(); iterator != list.end(); iterator++)
    {
        files->append(new QFileInfo(*iterator));
    }
    QPair< QList < QFileInfo * > *, QList < QDir * > * > *result = new QPair< QList < QFileInfo * > *, QList < QDir * > * >();
    result->first = files;
    result->second = dirs;
    return result;
}


/**
 * Filtruj po nazwach plikow 
 * @param files 
 */
void Finder::filterByName(QList< QFileInfo * > * files)
{
    QString regexpString = this->parameter->getParameters()->value(SearchParameter::FileName);
    regexpString.replace("*",".*");
    regexpString.replace("?",".");

    QRegExp *regexp = new QRegExp(regexpString);

    for (int i = files->count()-1; i>=0;i--)
    {
        if (!files->at(i)->fileName().contains(*regexp)) files->removeAt(i);
    }
    delete regexp;
}

/**
* Wczytywanie plików komentarzy
*/
QList< PictureListWidgetItem * > * Finder::decodeComments(QList< QFileInfo * > * files)
{

    QList< PictureListWidgetItem * > *result = new QList< PictureListWidgetItem * >();
    for (int i=files->count()-1;i>=0;i--)
    {
        result->append(new PictureListWidgetItem(*files->at(i)));
    }

    return result;
}


/**
 * Filtrowanie po notatkach (komentarzach)
 * @param files 
 */
void Finder::filterByNotes(QList< PictureListWidgetItem * > * files)
{

   QString regexpString = this->parameter->getParameters()->value(SearchParameter::Note);
    regexpString.replace("*",".*");
    regexpString.replace("?",".");

    QRegExp *regexp = new QRegExp(".*" + regexpString + ".*");

    for (int i = files->count()-1; i>=0;i--)
    {
        if (!files->at(i)->getNote().contains(*regexp)) files->removeAt(i);
    }
    delete regexp;

}

/**
 * Filtrowanie po miejscach
 * @param files 
 */
void Finder::filterByPlaces(QList< PictureListWidgetItem * > * files)
{
    QString regexpString = this->parameter->getParameters()->value(SearchParameter::Place);
    regexpString.replace("*",".*");
    regexpString.replace("?",".");
    QRegExp *regexp = new QRegExp(".*" + regexpString + ".*");
    for (int i = files->count()-1; i>=0;i--)
    {
        if (!files->at(i)->getPlace().contains(*regexp)) files->removeAt(i);
    }
    delete regexp;
}

/**
 *  Filter by keywords
 * @param files 
 */
void Finder::filterByKeywords(QList< PictureListWidgetItem * > * files)
{
    QSet<QString> *keys = this->parameter->getKeywords();
    for (int i = files->count()-1; i>=0;i--)
    {
        bool isVeryfied = false;
        for (QSet<QString>::const_iterator keyIterator = keys->begin(); keyIterator != keys->end(); keyIterator++)
        {
            if (files->at(i)->getKeywords()->contains(*keyIterator))
            {
                isVeryfied = true;
                break;
            }
        }
        if(!isVeryfied) files->removeAt(i);
    }
}

/**
 * Filter files by comment date
 * @param files 
 */
void Finder::filterByDate(QList< PictureListWidgetItem * > * files)
{
    QDateTime toDate = this->parameter->getDateParameter()->value(SearchParameter::DateStart);
    QDateTime fromDate = this->parameter->getDateParameter()->value(SearchParameter::DateEnd);
    for (int i = files->count()-1; i>=0;i--)
    {
        bool matchToDate = true;
        bool matchFromDate = true;
        if (toDate.isValid())
        {
            matchToDate = false;
            if (toDate<=files->at(i)->getDateTime()) matchToDate = true;
        }
        if (fromDate.isValid())
        {
            matchFromDate = false;
            if (fromDate>=files->at(i)->getDateTime()) matchFromDate = true;
        }
        if(!(matchToDate&&matchFromDate)){
         files->removeAt(i);
         }
    }
}

void Finder::sendResults(QList< PictureListWidgetItem * > * files)
{
	for(QList<PictureListWidgetItem*>::iterator i = files->begin(); i != files->end(); i++){
		(*i)->setIconImage(new QImage(Utils::generateIcon((*i)->getFile())));
	}
	QApplication::postEvent (this->eventHandler, new SearchUpdateEvent ( files) );
}




